package com.easylinkin.linkappapi.grid.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.exceptions.ExceptionEnum;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.grid.entity.GridAppraise;
import com.easylinkin.linkappapi.grid.entity.GridAppraiseCompany;
import com.easylinkin.linkappapi.grid.mapper.GridAppraiseMapper;
import com.easylinkin.linkappapi.grid.models.dto.GridAppraiseDTO;
import com.easylinkin.linkappapi.grid.models.dto.GridAppraiseFlagDTO;
import com.easylinkin.linkappapi.grid.models.query.GridAppraiseQuery;
import com.easylinkin.linkappapi.grid.models.vo.GridAppraiseExportVO;
import com.easylinkin.linkappapi.grid.service.IGridAppraiseCompanyService;
import com.easylinkin.linkappapi.grid.service.IGridAppraiseService;
import com.easylinkin.linkappapi.lobar.entity.LaborCompany;
import com.easylinkin.linkappapi.lobar.service.LaborCompanyService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 网格评比表 服务实现类
 *
 * @author
 * @since 2024-05-16
 */
@Slf4j
@Service
public class GridAppraiseServiceImpl extends ServiceImpl<GridAppraiseMapper, GridAppraise> implements IGridAppraiseService {

    @Autowired
    private LinkappUserContextProducer linkappUserContextProducer;
    @Autowired
    private IGridAppraiseCompanyService iGridAppraiseCompanyService;
    @Autowired
    private LaborCompanyService laborCompanyService;

    @Override
    public RestMessage queryPageList(RequestModel<GridAppraiseQuery> requestModel) {
        GridAppraiseQuery customQueryParams = requestModel.getCustomQueryParams();
        LinkappUser linkappUser = linkappUserContextProducer.getCurrent();
        IPage<GridAppraise> pageList = this.page(requestModel.getPage(), Wrappers.<GridAppraise>lambdaQuery()
                .eq(GridAppraise::getTenantId, linkappUser.getTenantId())
                .like(StrUtil.isNotBlank(customQueryParams.getAppraiseName()), GridAppraise::getAppraiseName, customQueryParams.getAppraiseName())
                .le(ObjectUtil.isNotNull(customQueryParams.getEndime()), GridAppraise::getCreateTime, customQueryParams.getEndime())
                .orderByDesc(GridAppraise::getCreateTime)
        );
        return RestBuilders.successBuilder().data(pageList).build();
    }

    /**
     * 新增评比配置
     *
     * @param gridAppraiseDTO:
     * @return site.morn.rest.RestMessage
     * @author Jereay
     * @date 2024/5/16 13:43
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestMessage addAppraise(GridAppraiseDTO gridAppraiseDTO) {
        GridAppraise gridAppraise = BeanUtil.copyProperties(gridAppraiseDTO, GridAppraise.class);
        LinkappUser linkappUser = linkappUserContextProducer.getCurrent();
        gridAppraise.setTenantId(linkappUser.getTenantId());
        gridAppraise.setCreateTime(LocalDateTime.now());
        gridAppraise.setCreatorId(linkappUser.getId().toString());
        Date date = DateUtil.date();
        String format1 = DateUtil.format(date, "yyyy-MM");
        int i = this.baseMapper.selectCountByDate(format1, linkappUser.getTenantId());
        if (i > 0) {
            return RestBuilders.errorBuilder().message(format1 + "评比已存在").build();
        }
        String format = DateUtil.format(date, "yyyy年MM月");
        gridAppraise.setAppraiseName(format + "网格片区评比");
        gridAppraise.setNeedCompanyCount(gridAppraiseDTO.getCompanyList().size());
        gridAppraise.setCompanyCount(0);
        boolean save = this.save(gridAppraise);
        if (save) {
            List<GridAppraiseCompany> companyList = new ArrayList<>();
            for (String companyId : gridAppraiseDTO.getCompanyList()) {
                GridAppraiseCompany gridAppraiseCompany = new GridAppraiseCompany();
                gridAppraiseCompany.setAppraiseId(gridAppraise.getId());
                gridAppraiseCompany.setCompanyId(companyId);
                // 查询单位名称
                LaborCompany laborCompany = laborCompanyService.getById(companyId);
                if (ObjectUtil.isNotNull(laborCompany)) {
                    gridAppraiseCompany.setCompanyName(laborCompany.getName());
                }
                companyList.add(gridAppraiseCompany);
            }
            boolean b = this.iGridAppraiseCompanyService.saveBatch(companyList);
            if (b) {
                return RestBuilders.successBuilder().message("新增成功").build();
            }
            throw new RuntimeException("评比单位保存失败");
        }
        return RestBuilders.errorBuilder().message("新增失败").build();
    }


    @Override
    public RestMessage setAppraiseFlag(GridAppraiseFlagDTO gridAppraiseFlagDTO) {
        GridAppraise gridAppraise = BeanUtil.copyProperties(gridAppraiseFlagDTO, GridAppraise.class);
        // 查询单位名称
        LaborCompany laborCompany = laborCompanyService.getById(gridAppraiseFlagDTO.getCompanyId());
        if (ObjectUtil.isNotNull(laborCompany)) {
            if (gridAppraiseFlagDTO.getType() == 1) {
                gridAppraise.setRedFlagCompanyId(gridAppraiseFlagDTO.getCompanyId());
                gridAppraise.setRedFlagCompanyName(laborCompany.getName());
            }
            if (gridAppraiseFlagDTO.getType() == 2) {
                gridAppraise.setYellowFlagCompanyId(gridAppraiseFlagDTO.getCompanyId());
                gridAppraise.setYellowFlagCompanyName(laborCompany.getName());
            }
            boolean b = this.updateById(gridAppraise);
            if (b) {
                return RestBuilders.successBuilder().message("添加成功").build();
            }
        }

        return RestBuilders.errorBuilder().message("添加失败").build();
    }

    @Override
    public byte[] export(GridAppraiseQuery query) {
        LinkappUser linkappUser = linkappUserContextProducer.getCurrent();

        List<GridAppraise> list = this.list(Wrappers.<GridAppraise>lambdaQuery()
                .eq(GridAppraise::getTenantId, linkappUser.getTenantId())
                .like(StrUtil.isNotBlank(query.getAppraiseName()), GridAppraise::getAppraiseName, query.getAppraiseName())
                .le(ObjectUtil.isNotNull(query.getEndime()), GridAppraise::getCreateTime, query.getEndime())
                .orderByDesc(GridAppraise::getCreateTime)
        );

        Set<Integer> appraiseIds = list.stream().map(GridAppraise::getId).collect(Collectors.toSet());

        Map<Integer, List<GridAppraiseCompany>> appraiseCompanyListMap = iGridAppraiseCompanyService.mapGroupByAppraiseId(appraiseIds);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
        ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);

        for (GridAppraise item : list) {
            GridAppraiseExportVO exportVO = new GridAppraiseExportVO(item, appraiseCompanyListMap.get(item.getId()));
            try {
                byte[] bytes = this.buildPdf(exportVO);

                zipOutputStream.putNextEntry(new ZipEntry(item.getAppraiseName() + ".pdf"));
                zipOutputStream.write(bytes);
                zipOutputStream.closeEntry();
            } catch (Exception e) {
                log.error("构建pdf失败 exportVO:{}", JSON.toJSONString(exportVO), e);
            }
        }

        // 总的zip ZipOutputStream close
        try {
            zipOutputStream.flush();
            //解决CRS校验失败问题
            zipOutputStream.finish();
            zipOutputStream.close();
            byteArrayOutputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return byteArrayOutputStream.toByteArray();
    }

    /**
     * @param exportVO 导出参数
     * @return byte
     * @author kyj
     * @date 2024/6/3 14:30
     */
    private byte[] buildPdf(GridAppraiseExportVO exportVO) throws Exception {
        String currentDir = System.getProperty("user.dir");
        String tempPath = currentDir + "/file/template/网格片区评比.pdf";
        PdfReader reader = null;
        try {
            reader = new PdfReader(tempPath);
        } catch (IOException e) {
            log.error("未找到模板 tempPath:{}", tempPath, e);
            throw new BusinessException(ExceptionEnum.CommonExceptionEnum.EXCEPTION_CODE_500, "未找到模板");
        }

        GridAppraise appraise = exportVO.getAppraise();
        List<GridAppraiseCompany> appraiseCompanyList = exportVO.getAppraiseCompanyList();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);

        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, bos);
        stamper.setFormFlattening(true);
        AcroFields form = stamper.getAcroFields();

        // 文字类的内容处理
        Map<String, String> datemap = new HashMap<>(4);
        datemap.put("appraiseName", appraise.getAppraiseName());
        datemap.put("endTime", DateUtil.format(appraise.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
        datemap.put("redFlagCompanyName", ObjectUtil.defaultIfBlank(appraise.getRedFlagCompanyName(), "-"));
        datemap.put("yellowFlagCompanyName", ObjectUtil.defaultIfBlank(appraise.getYellowFlagCompanyName(), "-"));
        form.addSubstitutionFont(bf);
        for (String key : datemap.keySet()) {
            String value = datemap.get(key);
            form.setField(key, value);
        }

        // 表格类
        Map<String, List<List<String>>> listMap = new HashMap<>(1);
        List<List<String>> tableGridAppraiseCompanyList = new ArrayList<>();
        List<String> titleItemTableList = CollUtil.toList("单位", "进度得分", "质量得分", "安全得分", "文明施工得分", "总分");
        tableGridAppraiseCompanyList.add(titleItemTableList);
        for (GridAppraiseCompany appraiseCompany : appraiseCompanyList) {
            List<String> itemTableList = CollUtil.toList(
                    appraiseCompany.getCompanyName(),
                    String.valueOf(ObjectUtil.defaultIfNull(appraiseCompany.getScheduleScore(), "-")),
                    String.valueOf(ObjectUtil.defaultIfNull(appraiseCompany.getQualityScore(), "-")),
                    String.valueOf(ObjectUtil.defaultIfNull(appraiseCompany.getSafetyScore(), "-")),
                    String.valueOf(ObjectUtil.defaultIfNull(appraiseCompany.getConstructionScore(), "-")),
                    String.valueOf(ObjectUtil.defaultIfNull(appraiseCompany.getTotalScore(), "-")));
            tableGridAppraiseCompanyList.add(itemTableList);
        }
        listMap.put("appraiseCompanyList", tableGridAppraiseCompanyList);

        for (String key : listMap.keySet()) {
            List<List<String>> lists = listMap.get(key);
            int pageNo = form.getFieldPositions(key).get(0).page;
            PdfContentByte pcb = stamper.getOverContent(pageNo);
            Rectangle signRect = form.getFieldPositions(key).get(0).position;
            //表格位置
            int column = lists.get(0).size();
            int row = lists.size();
            PdfPTable table = new PdfPTable(column);
            float tatalWidth = signRect.getRight() - signRect.getLeft() - 1;
            int size = lists.get(0).size();
            float width[] = new float[size];
            for (int i = 0; i < size; i++) {
                if (i == 0) {
                    width[i] = 60f;
                } else {
                    width[i] = (tatalWidth - 60) / (size - 1);
                }
            }
            table.setTotalWidth(width);
            table.setLockedWidth(true);
            table.setKeepTogether(true);
            table.setSplitLate(false);
            table.setSplitRows(true);
            Font FontProve = new Font(bf, 10, 0);
            //表格数据填写
            for (int i = 0; i < row; i++) {
                List<String> list = lists.get(i);
                for (int j = 0; j < column; j++) {
                    Paragraph paragraph = new Paragraph(String.valueOf(list.get(j)), FontProve);
                    PdfPCell cell = new PdfPCell(paragraph);
                    cell.setBorderWidth(1);
                    cell.setVerticalAlignment(Element.ALIGN_CENTER);
                    cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                    cell.setLeading(0, (float) 1.4);
                    table.addCell(cell);
                }
            }
            table.writeSelectedRows(0, -1, signRect.getLeft(), signRect.getTop(), pcb);
        }
        // 如果为false，生成的PDF文件可以编辑，如果为true，生成的PDF文件不可以编辑
        stamper.setFormFlattening(true);
        stamper.close();
        reader.close();
        Document doc = new Document();
        PdfCopy copy = new PdfCopy(doc, byteArrayOutputStream);
        doc.open();
        int pageNum = reader.getNumberOfPages();
        for (int i = 1; i <= pageNum; i++) {
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);
            copy.addPage(importPage);
        }
        doc.close();

        return byteArrayOutputStream.toByteArray();
    }
}